﻿
using System;
using System.Collections.Generic;
using System.Text;
using System.Web;

namespace CatEars.Core.Net
{
    /// <summary>
    /// Url请求参数
    /// </summary>
    public class UrlBuilder
    {
        /// <summary>
        /// 默认构造方法
        /// </summary>
        /// <param name="strUrl">网址</param>
        public UrlBuilder(string strUrl)
            : this(strUrl, null)
        {
        }

        /// <summary>
        /// 构造方法
        /// </summary>
        /// <param name="strUrl">网址</param>
        /// <param name="param">参数字典</param>
        public UrlBuilder(string strUrl, Dictionary<string, string> param)
        {
            if (param == null)
            {
                param = new Dictionary<string, string>();

                int intIndex = strUrl.IndexOf('?');
                if (intIndex >= 0)
                {
                    string strParam = strUrl.Substring(intIndex + 1);
                    strUrl = strUrl.Substring(0, intIndex);
                    param = DecodeUrlParam(strParam);
                }
            }
            Url = strUrl;
            Params = param;
        }

        /// <summary>
        /// 用于Url参数解析
        /// </summary>
        /// <param name="strParam"></param>
        /// <returns></returns>
        public static Dictionary<string, string> DecodeUrlParam(string strParam)
        {
            Dictionary<string, string> result = new Dictionary<string, string>();
            if (string.IsNullOrEmpty(strParam))
            {
                return result;
            }
            StringBuilder strKey = new StringBuilder();
            StringBuilder strValue = new StringBuilder();
            int intMode = 0;
            for (int i = 0; i < strParam.Length; i++)
            {
                char chr = strParam[i];
                if (chr == '&')
                {
                    if (strKey.Length > 0)
                    {
                        result[HttpUtility.UrlDecode(strKey.ToString())]
                            = HttpUtility.UrlDecode(strValue.ToString());
                    }
                    strKey.Clear();
                    strValue.Clear();
                    intMode = 0;
                }
                else if (chr == '=')
                {
                    intMode = 1;
                }
                else
                {
                    if (intMode == 0) strKey.Append(chr);
                    else strValue.Append(chr);
                }
            }
            if (strKey.Length > 0)
            {
                result[HttpUtility.UrlDecode(strKey.ToString())]
                    = HttpUtility.UrlDecode(strValue.ToString());
            }
            return result;
        }

        #region 基本属性
        /// <summary>
        /// 是否为Https协议
        /// </summary>
        public bool IsHttps { get; set; }

        /// <summary>
        /// 网址
        /// </summary>
        private string m_strUrl;

        /// <summary>
        /// 网址
        /// </summary>
        public string Url
        {
            get { return m_strUrl; }
            set
            {
                m_strUrl = value;
                IsHttps = m_strUrl.StartsWith("https", StringComparison.OrdinalIgnoreCase);
            }
        }

        /// <summary>
        /// 值已经进行了转义，处理时不需要再转义
        /// </summary>
        public bool ValueHasUrlEncoded { get; set; }

        /// <summary>
        /// 参数(Value为null为动态参数，设置好参数后执行Compile方法)
        /// </summary>
        public Dictionary<string, string> Params { get; private set; }
        #endregion

        #region Url参数编译
        /// <summary>
        /// 编译结果 未编译时为null [0]为nul 后面的为可变Key名称
        /// </summary>
        public string[] CompileResult { get; private set; }

        /// <summary>
        /// 对参数进行编译（提前合并固定参数）Params中value为null的为可变的部分
        /// </summary>
        public void Compile()
        {
            CompileResult = Compile(Url, Params, IsHttps, true, ValueHasUrlEncoded);
        }

        /// <summary>
        /// 对参数进行编译
        /// </summary>
        /// <param name="strUrl">网址</param>
        /// <param name="param">参数</param>
        /// <param name="blnIsHttps">是否Https</param>
        /// <param name="blnAllowNullValue">允许param的Value有null值</param>
        /// <param name="blnValueHasUrlEncoded">值已经进行了转义，处理时不需要再转义</param>
        /// <returns>编译结果</returns>
        private static string[] Compile(string strUrl,
            Dictionary<string, string> param,
            bool blnIsHttps,
            bool blnAllowNullValue,
            bool blnValueHasUrlEncoded)
        {
            List<string> result = new List<string>();
            result.Add(null);
            StringBuilder strFinalUrl = new StringBuilder();
            if (!strUrl.StartsWith("http", StringComparison.OrdinalIgnoreCase))
            {
                if (blnIsHttps)
                {
                    strFinalUrl.Append("https://");
                }
                else
                {
                    strFinalUrl.Append("http://");
                }
            }
            strFinalUrl.Append(strUrl);
            if (strFinalUrl[strFinalUrl.Length - 1] != '?')
            {
                strFinalUrl.Append('?');
            }
            foreach (var item in param)
            {
                //item.Key没有用HttpUtility.UrlEncode进行转义
                strFinalUrl.Append(item.Key);
                strFinalUrl.Append("=");
                string strValue = item.Value;
                if (strValue == null)
                {
                    if (blnAllowNullValue)
                    {
                        strFinalUrl.Append('{');
                        strFinalUrl.Append(result.Count - 1);
                        strFinalUrl.Append('}');
                        result.Add(item.Key);
                    }
                    else
                    {
                        throw new Exception(string.Format("参数字典的Value不可为null,Key=\"{0}\"", item.Key));
                    }
                }
                else if (blnValueHasUrlEncoded)
                {
                    strFinalUrl.Append(strValue);
                }
                else
                {
                    if (strValue.Contains("%"))
                    {
                        // %25 就是 % 的转义 防止strValue本身就是已经转义的串重复转义
                        strFinalUrl.Append(HttpUtility.UrlEncode(strValue).Replace("%25", "%"));
                    }
                    else
                    {
                        strFinalUrl.Append(HttpUtility.UrlEncode(strValue));
                    }
                }
                strFinalUrl.Append('&');
            }
            strFinalUrl.Length--;
            result[0] = strFinalUrl.ToString();
            return result.ToArray();
        }
        #endregion

        /// <summary>
        /// 获取完整的Url
        /// </summary>
        /// <returns>返回值</returns>
        public string GetFullUrl()
        {
            if (CompileResult.IsNullOrEmptyT())
            {
                Compile();
                return GetFullUrl();
            }
            else
            {
                if (CompileResult.Length == 1)
                {
                    return CompileResult[0];
                }
                else
                {
                    object[] objs = new object[CompileResult.Length - 1];
                    for (int i = 0; i < objs.Length; i++)
                    {
                        string strValue;
                        if (Params.TryGetValue(CompileResult[i + 1], out strValue))
                        {
                            if (strValue != null)
                            {
                                objs[i] = HttpUtility.UrlEncode(strValue);
                            }
                        }
                    }
                    return string.Format(CompileResult[0], objs);
                }
            }
        }
    }
}
